#ifndef __STACK_INCLUDE
#define __STACK_INCLUDE

/** Templated implementation of a Stack data structure */
template <class T>
class Stack {
	
	public:		
		/** Default constructor that initializes the stack to a 
			specific size.
			Parameters:
				size - the number of elements in the stack
		*/
		Stack<T>(int);
		
		/** Destructor for the Stack.  Deletes the elements array */
		~Stack();
		
		/** Pushes an element to the top of the stack.
			Parameters:
				element - the element to push on top of the stack
		*/
		void push(T);
		
		/** Pops an element off the stack and returns it.
			Return:
				The element on top of the stack
		*/
		T pop();
		
		/** Returns the top element off the stack without modifying the stack.
			Return:
				The element on top of the stack
		*/
		T peek();
		
		/** Indicates if there are elements on the stack or not.
			Return:
				true if the stack has elements, false otherwise
		*/
		bool isEmpty();
		
	private:
		/* array of elements representing the stack */
		T* elements;

		/* the size of each element */
		int elementSize;
				
		/* pointer to the top  */
		T* top;
		
		/* pointer to the last element of the stack */
		T* max;
};

// see above
template <class T>
Stack<T>::Stack(int size) {
	cout << "Creating stack of size " << size << "\n";
	this->elements = new T[size];
	this->top = this->elements;
	this->elementSize = sizeof(T);
	this->max = this->elements + size;
}

// see above
template <class T>
Stack<T>::~Stack() {
	delete[] this->elements;
}

// see above
template <class T>
void Stack<T>::push(T element) {
	// Check to see if we're already at the top of the stack
	if (this->top == this->max) {
		cout << "\nERROR: Push(" << element << ") failed, stack at maximum capacity!\n";
		exit(0);
	} else {
		this->top++;
		*this->top = element;
	}
}

// see above
template <class T>
T Stack<T>::pop() {
	T element = *this->top;
	if (this->top != this->elements) {
		this->top--;		
	}
	return element;
}

// see above
template <class T>
T Stack<T>::peek() {
    return *this->top;
}

// see above
template <class T>
bool Stack<T>::isEmpty() {
	bool isEmpty = false;
	if (this->top == this->elements) {
		isEmpty = true;
	}
	return isEmpty;
}

#endif